from strange_io import SIGNATURE, get_format, _load_bytearray
from strange_io.text import StrangeText
import strange_io.dynamic_integer as dynamic_integer

class StrangeDictionary:
    def __init__(self, dictionary:dict={}):
        self.dictionary: dict = dictionary

    def dump(self) -> dict:
        return self.dictionary

    def load(self, dictionary:dict):
        self.dictionary = dictionary

    def dump_bytes(self) -> bytes:
        return self.encode(self.dictionary)

    def load_bytes(self, data: bytes):
        self.dictionary = self.decode(data)

    def dump_file(self, path):
        out_file = bytearray()
        header = bytearray(SIGNATURE + b'dictionary\n')
        out_file += header
        out_file += self.encode(self.dictionary)
        with open(path, 'wb') as f:
            f.write(out_file)

    def load_file(self, path, ignore_type=False):
        if get_format(path) == b'dictionary' or ignore_type:
            file = _load_bytearray(path, remove_type=True)
            self.dictionary = self.decode(file)
        else:
            raise TypeError('Attempted to load non-dictionary document as dictionary document')

    @staticmethod
    def encode(dictionary: dict) -> bytes:
        text = StrangeText()
        number = len(dictionary)
        out = bytes()
        out += dynamic_integer.encode(number)[0]
        for key in dictionary:
            item = dictionary[key]
            #region key
            number = len(key)
            out += dynamic_integer.encode(number)[0]
            text.load(key)
            out += text.dump_bytes()
            #endregion
            #region item
            number = len(item)
            out += dynamic_integer.encode(number)[0]
            out += item
            #endregion
        return out

    @staticmethod
    def decode(data:bytes) -> dict:
        text = StrangeText()
        out = {}
        data = bytearray(data)
        dictionary_length = dynamic_integer.decode(data)[0]
        for _ in range(dictionary_length):
            #region key
            key_length = dynamic_integer.decode(data)[0]
            _bytes = bytearray()
            for _ in range(key_length):
                _bytes.append(data[0])
                del data[0]
            text.load_bytes(_bytes)
            key = text.dump()
            #endregion
            #region value
            value_length = dynamic_integer.decode(data)[0]
            _bytes = bytearray()
            for _ in range(value_length):
                _bytes.append(data[0])
                del data[0]
            value = bytes(_bytes)
            #endregion
            out[key] = value
        return (out)

#region dictionary-like
    def pop(self, index=None):
        return self.dictionary.pop(index)

    def __getitem__(self, index):
        return self.dictionary[index]

    def __setitem__(self, index, dictionary):
        self.dictionary[index] = dictionary

    def __len__(self):
        return len(self.dictionary)

    def __str__(self):
        return str(self.dictionary)
#endregion
